Scenario #9730: An Api Key Is Not Revoked If the Safeguard Parameters Do Not Match

DELETE /api/rbac/subjects/{uuid} has to repeat the subject’s name and type as safeguard query parameters, which are verified against the subject identified by the UUID in the path. If they do not match, nothing is deleted: the request is rejected with 400 Bad Request and the API-key keeps authenticating.

Properties

Given

name value
subjectUuid a91c000c-0000-0000-0000-00000000000c
subjectName revoke.attempt.key

API_KEY subjects authenticate technical clients via the Hostsharing-Api-Key HTTP header instead of a Keycloak OIDC JWT, e.g. automation programs, completely bypassing Keycloak. Only a global-admin may create API_KEY subjects. The clear-text API-key is returned only once, in the response of creating the API_KEY subject; just its hash gets stored. Like GROUP subjects, API_KEY subjects cannot have an account. Global API_KEY subjects do not belong to a realm, thus their name must neither contain a - (the realm-prefix delimiter) nor a / (the GROUP subject marker).

Create the API_KEY Subject

The response contains the generated clear-text API-key (property apiKey) exactly once; it cannot be retrieved again.

HTTP POST "/api/rbac/subjects" \
  -H "Authorization: Bearer $HSADMINNG_JWT_BEARER" \
  `# {` \
  `#   "sub" : "uuid<hsh-alex_superuser>"` \
  `# }` \
  <<EOF
{
  "uuid" : "a91c000c-0000-0000-0000-00000000000c",
  "name" : "revoke.attempt.key",
  "type" : "API_KEY"
}
EOF
=> status: 201 CREATED a91c000c-0000-0000-0000-00000000000c
{
  "uuid" : "a91c000c-0000-0000-0000-00000000000c",
  "name" : "revoke.attempt.key",
  "organization" : "revoke",
  "type" : "API_KEY",
  "apiKey" : "hsak_revoke.attempt.key.cb16b91b5f1b0477a484ecb207a163c17526bf9edb057f620e40a6b40b535ace",
  "scopes" : null,
  "expiresAt" : null
}

Prerequisite: Resolve the UUID of the global ADMIN role

The grant API needs the UUID of the role which we want to grant.

HTTP GET "/api/rbac/roles?name=rbac.global%23global%3AADMIN" \
  -H "Authorization: Bearer $HSADMINNG_JWT_BEARER" \
  `# {` \
  `#   "sub" : "uuid<hsh-alex_superuser>"` \
  `# }`
=> status: 200 OK 
[ {
  "uuid" : "7ea7e6cb-16dd-4fb9-aa82-427df5f205d7", // globalAdminRoleUuidToGrant
  "object.uuid" : "6ec9aacc-2bd3-4678-a8f9-31e61eef3b0a",
  "objectTable" : "rbac.global",
  "objectIdName" : "global",
  "roleType" : "ADMIN",
  "roleName" : "rbac.global#6ec9aacc-2bd3-4678-a8f9-31e61eef3b0a:ADMIN",
  "roleIdName" : "rbac.global#global:ADMIN"
} ]

Grant the global ADMIN role to the API_KEY Subject

HTTP POST "/api/rbac/grants" \
  -H "Authorization: Bearer $HSADMINNG_JWT_BEARER" \
  `# {` \
  `#   "sub" : "uuid<hsh-alex_superuser>"` \
  `# }` \
  -H 'Hostsharing-Assumed-Roles: rbac.global#global:ADMIN' \
  <<EOF
{
  "assumed" : true,
  "grantedRole.uuid" : "7ea7e6cb-16dd-4fb9-aa82-427df5f205d7", // globalAdminRoleUuidToGrant
  "granteeSubject.uuid" : "a91c000c-0000-0000-0000-00000000000c"
}
EOF
=> status: 201 CREATED 7ea7e6cb-16dd-4fb9-aa82-427df5f205d7 // globalAdminRoleUuidToGrant

Verify the API-key authenticates as its Subject with the global-admin role, without any JWT

HTTP GET "/api/hs/accounts/current" \
  -H "Hostsharing-Api-Key: $HSADMINNG_API_KEY"
=> status: 200 OK 
{
  "subject" : {
    "uuid" : "a91c000c-0000-0000-0000-00000000000c",
    "name" : "revoke.attempt.key",
    "organization" : "revoke",
    "type" : "API_KEY"
  },
  "person" : null,
  "globalAdmin" : true
}

Attempt to delete the API_KEY subject with a mismatching name

HTTP DELETE "/api/rbac/subjects/a91c000c-0000-0000-0000-00000000000c?name=revoke.attempt.key.mismatch&type=API_KEY" \
  -H "Authorization: Bearer $HSADMINNG_JWT_BEARER" \
  `# {` \
  `#   "sub" : "uuid<hsh-alex_superuser>"` \
  `# }`
=> status: 400 BAD_REQUEST 
{
  "timestamp" : "2026-08-10 01:38:09",
  "path" : "",
  "statusCode" : 400,
  "statusPhrase" : "Bad Request",
  "message" : "ERROR: [400] Both (name from query-parameter, name of the subject to delete) must be equal, but are (revoke.attempt.key.mismatch, revoke.attempt.key)"
}

generated on 2026-08-10 01:38:09 for branch